﻿/*
 * Created by SharpDevelop.
 * User: ratul
 * Date: 3/2/2010
 * Time: 7:50 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;

namespace H264Impl.NET.NAL
{
	/// <summary>
	/// Description of NALUnit.
	/// </summary>
	public class NALUnit
	{
		public NALUnit()
		{
		}
		
		public NALUnit(BitStream _NALUnitBitStream, bool forbiddenZeroBit, UInt32 NALRefIdc, UInt32 nalUnitType )
		{
			this.forbiddenZeroBit = forbiddenZeroBit;
			this.NALRefIdc = NALRefIdc;
			
			this.RBSP = _NALUnitBitStream;
			
			
			if(_NALUnitType==NALUnitType.CODED_SLICE_OF_IDR_PICTURE)
				IDRPicFlag = true;
			else 
				IDRPicFlag = false;
			
			setNALUnitType(nalUnitType);
				
			validatefields();
		}
		public BitStream getRBSP()
		{
			return RBSP;
		}
		public NALUnitType getNALUnitType()
		{
			return _NALUnitType;
		}
		
		void setNALUnitType(UInt32 nalUnitType )
		{
			switch(nalUnitType)
			{
				case 1:
					_NALUnitType = NALUnitType.CODED_SLICE_OF_NON_IDR_PICTURE; break;
				case 2: 
					_NALUnitType = NALUnitType.CODED_SLICE_DATA_PARTITION_A; break;
				case 3:
					_NALUnitType = NALUnitType.CODED_SLICE_DATA_PARTITION_B; break;
				case 4: 
					_NALUnitType = NALUnitType.CODED_SLICE_DATA_PARTITION_C; break;
				case 5: 
					_NALUnitType = NALUnitType.CODED_SLICE_OF_IDR_PICTURE; break;
				case 6:
					_NALUnitType = NALUnitType.SUPPLEMENTAL_ENHANCEMENT_INFORMATION; break;
				case 7:
					_NALUnitType = NALUnitType.SEQUENCE_PARAMETER_SET; break;
				case 8:
					_NALUnitType = NALUnitType.PICTURE_PARAMETER_SET; break;
				case 9:
					_NALUnitType = NALUnitType.ACCESS_UNIT_DELIMITER; break;
				case 10:
					_NALUnitType = NALUnitType.END_OF_SEQUENCE; break;
				case 11:
					_NALUnitType = NALUnitType.END_OF_STREAM; break;
				case 12:
					_NALUnitType = NALUnitType.FILLER_DATA; break;
				case 13: 
					_NALUnitType = NALUnitType.SEQUENCE_PARAMETER_SET_EXTENSION; break;
				case 14: 
					_NALUnitType = NALUnitType.PREFIX_NAL_UNIT; break;
				case 15: 
					_NALUnitType = NALUnitType.SUBSET_SEQUENCE_PARAMETER_SET; break;
				case 19:
					_NALUnitType = NALUnitType.CODED_SLICE_OF_AUXILIARY_CODED_PICTUREWITHOUT_PARTITIONING; break;
				case 20: 
					_NALUnitType = NALUnitType.CODED_SLICE_EXTENSION; break;
			}
		}
		
		void validatefields()
		{
			if(forbiddenZeroBit != false)
				throw new ArgumentException();
			
			//1) if NALRefIdc==0 && _NALUnitType==1TO4, then all NAL units in the picture shld have the same
			//2) nal_ref_idc equal to 0 for a NAL unit containing a slice or slice data partition
			//   indicates that the slice or slice data partition is part of a non-reference picture.
			//3) When the value of nal_unit_type is equal to 5 for a NAL unit containing a slice of a particular
			//   picture, the picture shall not contain NAL units with nal_unit_type in the range of 1 to 4, inclusive
			//These 3 need to be verified later at the slice level
			//please see the slice code
			
			if(NALRefIdc==0 && (_NALUnitType==NALUnitType.SEQUENCE_PARAMETER_SET || _NALUnitType==NALUnitType.SEQUENCE_PARAMETER_SET_EXTENSION || _NALUnitType==NALUnitType.SUBSET_SEQUENCE_PARAMETER_SET || _NALUnitType==NALUnitType.PICTURE_PARAMETER_SET))
				throw new H264ImplConformanceException();
				
			if(NALRefIdc==0 && _NALUnitType==NALUnitType.CODED_SLICE_OF_IDR_PICTURE)
				throw new H264ImplConformanceException();
			
			if(_NALUnitType==NALUnitType.SUPPLEMENTAL_ENHANCEMENT_INFORMATION || _NALUnitType==NALUnitType.ACCESS_UNIT_DELIMITER || _NALUnitType==NALUnitType.END_OF_SEQUENCE || _NALUnitType==NALUnitType.END_OF_STREAM || _NALUnitType==NALUnitType.FILLER_DATA)
				if(NALRefIdc!=0)
					throw new H264ImplConformanceException();
		}
		char[] NALPayload;
		UInt16 DON; //decoding order number
		char emulationPreventionByte;
		
		
		UInt32 numBytesInNALUnit;
		protected bool forbiddenZeroBit;
		protected UInt32 NALRefIdc; 
		protected BitStream RBSP;
		
		
		//byte[] RBSP;
		bool IDRPicFlag;
		
		public bool getIDRPicFlag()
		{
			return IDRPicFlag;
		}
		
		NALUnitType _NALUnitType;
		public enum NALUnitType
		{
			UNSPECIFIED = 0,
			CODED_SLICE_OF_NON_IDR_PICTURE,
			CODED_SLICE_DATA_PARTITION_A,
			CODED_SLICE_DATA_PARTITION_B,
			CODED_SLICE_DATA_PARTITION_C,
			CODED_SLICE_OF_IDR_PICTURE,
			SUPPLEMENTAL_ENHANCEMENT_INFORMATION,
			SEQUENCE_PARAMETER_SET,
			PICTURE_PARAMETER_SET,
			ACCESS_UNIT_DELIMITER,
			END_OF_SEQUENCE,
			END_OF_STREAM,
			FILLER_DATA,
			SEQUENCE_PARAMETER_SET_EXTENSION,
			PREFIX_NAL_UNIT,
			SUBSET_SEQUENCE_PARAMETER_SET,
			RESERVERD1,
			RESERVERD2,
			RESERVERD3,
			CODED_SLICE_OF_AUXILIARY_CODED_PICTUREWITHOUT_PARTITIONING,
			CODED_SLICE_EXTENSION,
			RESERVERD4,
			RESERVERD5,
			RESERVERD6,
			UNSPECIFIED1,
			UNSPECIFIED2,
			UNSPECIFIED3,
			UNSPECIFIED4,
			UNSPECIFIED5,
			UNSPECIFIED6,
			UNSPECIFIED7,
			UNSPECIFIED8

		}
		

	}
}
